EnableExplicit

XIncludeFile "auto size test.pb"

Enumeration 1000
  #PB_GadgetType_Window
  #PB_GadgetType_HBox
  #PB_GadgetType_VBox
  #PB_GadgetType_Spacer
;  #PB_GadgetType_
;  #PB_GadgetType_
;  #PB_GadgetType_
;  #PB_GadgetType_
;  #PB_GadgetType_
EndEnumeration

Structure Control
  Node.i
  ParentNode.i
  
  Type.i
  Name.s
  Text.s
  SizingHorizontally.i
  SizingVertically.i
  
  Path.s
  GeneralType.b
EndStructure


Procedure.i AddControl(List Controls.Control(), pParentNode.i, pGadgetType.i, pGadgetName.s, pGadgetText.s, pSizingHorizontally.i, pSizingVertically.i, pPath.s)
  AddElement(Controls())
  
  Controls()\Node = ListSize(Controls())
  Controls()\ParentNode = pParentNode
  Controls()\Type = pGadgetType
  Controls()\Name = pGadgetName
  Controls()\Text = pGadgetText
  Controls()\SizingHorizontally = pSizingHorizontally
  Controls()\SizingVertically = pSizingVertically
  Controls()\Path = pPath
  
  If pGadgetType = #PB_GadgetType_Window
    Controls()\GeneralType = #GeneralType_Window
  ElseIf pGadgetType = #PB_GadgetType_HBox Or pGadgetType = #PB_GadgetType_VBox Or pGadgetType = #PB_GadgetType_Frame3D
    Controls()\GeneralType = #GeneralType_Container
  Else
    Controls()\GeneralType = #GeneralType_Gadget
  EndIf

  ProcedureReturn Controls()\Node 
EndProcedure

Procedure FillKeyWords(Map kw.i())
  kw("button") = #PB_GadgetType_Button
  kw("checkbox") = #PB_GadgetType_CheckBox
  kw("option") = #PB_GadgetType_Option
  kw("text") = #PB_GadgetType_Text
  kw("string") = #PB_GadgetType_String
  kw("combobox") = #PB_GadgetType_ComboBox
  kw("image") = #PB_GadgetType_Image
  kw("gbox") = #PB_GadgetType_Frame3D
 
  kw("window") = #PB_GadgetType_Window
  kw("hbox") = #PB_GadgetType_HBox
  kw("vbox") = #PB_GadgetType_VBox
  kw("spacer") = #PB_GadgetType_Spacer
EndProcedure

Procedure.s KeyWord_FindNameByID(Map kw.i(), id.i)
  ForEach kw()
    If kw()=id
      ProcedureReturn MapKey(kw())
    EndIf
  Next
EndProcedure

Procedure.i KeyWord_FindIDByName(Map kw.i(), name.s)
  ProcedureReturn kw(LCase(name))
EndProcedure

Procedure FillControls(Map kw.i(), List Controls.Control(), *pCurrentNode, pParentNode = -1)
  If XMLNodeType(*pCurrentNode) <> #PB_XML_Normal
    ProcedureReturn 
  EndIf
  
  Protected GadgetTypeID.i = KeyWord_FindIDByName(kw(), LCase(GetXMLNodeName(*pCurrentNode)))
  
  NewMap Attribute.s()

  If ExamineXMLAttributes(*pCurrentNode)
    While NextXMLAttribute(*pCurrentNode)
      Attribute(XMLAttributeName(*pCurrentNode)) = XMLAttributeValue(*pCurrentNode)
    Wend
  EndIf

  Protected CurrentNode.i = AddControl(Controls(), pParentNode, GadgetTypeID, Attribute("Name"), Attribute("Text"), Val(Attribute("SizingHorizontally")), Val(Attribute("SizingVertically")), Attribute("Path"))
  
  ; Now get the first child node (if any)
  ;    
  Protected *ChildNode.i = ChildXMLNode(*pCurrentNode)
  
  ; Loop through all available child nodes and call this procedure again
  ;
  While *ChildNode <> 0
    FillControls(kw(), Controls(), *ChildNode, CurrentNode)
    *ChildNode = NextXMLNode(*ChildNode)
  Wend
EndProcedure

NewMap KeyWords.i()
NewList Controls.Control()

FillKeyWords(KeyWords())

#XML = 0
If LoadXML(#XML, "example.xml")
    If XMLStatus(#XML) <> #PB_XML_Success
      Define Message$
      Message$ = "Error in the XML file:" + Chr(13)
      Message$ + "Message: " + XMLError(#XML) + Chr(13)
      Message$ + "Line: " + Str(XMLErrorLine(#XML)) + "   Character: " + Str(XMLErrorPosition(#XML))
      MessageRequester("Error", Message$)
      
      End
    EndIf
Else
  MessageRequester("Error", "Failed to load XML file.")
  End
EndIf

Define *MainNode = MainXMLNode(#XML)
If *MainNode
  FillControls(KeyWords(), Controls(), *MainNode)
EndIf



;ForEach Controls()
;Debug Controls()\Name + "    " + Str(Controls()\ParentNode) + " :: " + Str(Controls()\Node) + "    " + Str(Controls()\GeneralType) + " :: " + Str(Controls()\Type)
;Next

Global NewList gadgets.GadgetLayout()
Global NewList images.i()

Procedure FillGadgets(List Controls.Control(), List gadgets.GadgetLayout(), ParentNode = -1, ParentID = -1)
  ForEach Controls()
    If Controls()\ParentNode = ParentNode

      If Controls()\GeneralType = #GeneralType_Window
        AddElement(gadgets())
        gadgets()\ID = ListSize(gadgets())
        OpenWindow(gadgets()\ID, 0, 0, 0, 0, Controls()\Text,  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)

        gadgets()\GeneralType = #GeneralType_Window
        gadgets()\Type = #PB_GadgetType_Window

        Protected *tmpControl.i = @Controls()
        FillGadgets(Controls(), gadgets(), Controls()\Node, gadgets()\ID)
        ChangeCurrentElement(Controls(), *tmpControl)
      Else
        AddElement(gadgets())
        gadgets()\ID = ListSize(gadgets())

        Select Controls()\Type
        Case #PB_GadgetType_Button
          ButtonGadget(gadgets()\ID, 0, 0, 0, 0, Controls()\Text)
        Case #PB_GadgetType_CheckBox
          CheckBoxGadget(gadgets()\ID, 0, 0, 0, 0, Controls()\Text)
        Case #PB_GadgetType_ComboBox
          ComboBoxGadget(gadgets()\ID, 0, 0, 0, 0)
        Case #PB_GadgetType_Image
          gadgets()\ItemID = LoadImage(#PB_Any, Controls()\Path)
          ImageGadget(gadgets()\ID, 0, 0, 0, 0, gadgets()\ItemID)
        Case #PB_GadgetType_Option
          OptionGadget(gadgets()\ID, 0, 0, 0, 0, Controls()\Text)
        Case #PB_GadgetType_String
          StringGadget(gadgets()\ID, 0, 0, 0, 0, Controls()\Text)
        Case #PB_GadgetType_Text
          TextGadget(gadgets()\ID, 0, 0, 0, 0, Controls()\Text)
        Case #PB_GadgetType_Frame3D
          Frame3DGadget(gadgets()\ID, 0, 0, 20, 20, Controls()\Text)

        ; specials
        Case #PB_GadgetType_HBox, #PB_GadgetType_VBox
          ContainerGadget(gadgets()\ID, 0, 0, 20, 20) ; , #PB_Container_Single
        Case #PB_GadgetType_Spacer
          gadgets()\ID = 0
        EndSelect
      
        If gadgets()\ID <> 0
          GetRequiredSize(gadgets()\ID, @gadgets()\MinWidth, @gadgets()\MinHeight)
        Else
          gadgets()\MinWidth = 0
          gadgets()\MinHeight = 0
        EndIf
        
        gadgets()\ParentID =  ParentID
        gadgets()\GeneralType = Controls()\GeneralType
        gadgets()\Type = Controls()\Type

        gadgets()\FlexWidthType = Controls()\SizingHorizontally
        gadgets()\FlexHeightType = Controls()\SizingVertically
    
        gadgets()\Name = Controls()\Name

        If Controls()\Type = #PB_GadgetType_HBox
          gadgets()\Orientation = #Orientation_Horizontal
        Else
          gadgets()\Orientation = #Orientation_Vertical
        EndIf

        If Controls()\GeneralType = #GeneralType_Container
          *tmpControl.i = @Controls()
          FillGadgets(Controls(), gadgets(), Controls()\Node, gadgets()\ID)
          ChangeCurrentElement(Controls(), *tmpControl)

          If Controls()\Type <> #PB_GadgetType_Frame3D
            CloseGadgetList()
          EndIf
        EndIf

      EndIf
    EndIf
  Next
  
EndProcedure

FillGadgets(Controls(), gadgets())
FirstElement(gadgets())

Procedure RenderGadgets(pCalculateMinimumSize.b)
  ForEach gadgets()
    If gadgets()\Type = #PB_GadgetType_Window
      Protected WinWidth.i = WindowWidth(gadgets()\ID)
      Protected WinHeight.i = WindowHeight(gadgets()\ID)
      Protected minWidth.i, minHeight.i
      
      Protected *tmpGadget.i = @gadgets()
      CalculateMinimumSizes(#Orientation_Vertical, gadgets(), gadgets()\ID, @minWidth, @minHeight, 8, 8, 8, 8)
      ChangeCurrentElement(gadgets(), *tmpGadget)
      gadgets()\MinWidth = minWidth
      gadgets()\MinHeight = minHeight
  
      Protected ResizeToMin.b = #False
      If WinWidth < minWidth : WinWidth = minWidth : ResizeToMin = #True : EndIf
      If WinHeight < minHeight : WinHeight = minHeight : ResizeToMin = #True : EndIf
  
      If ResizeToMin = #True
        ResizeWindow(gadgets()\ID, #PB_Ignore, #PB_Ignore, WinWidth, WinHeight)
      EndIf
      
      OrientGadgets(#Orientation_Vertical, gadgets(), gadgets()\ID, minWidth, minHeight, @WinWidth, @WinHeight, 8, 8, 8, 8)
      ChangeCurrentElement(gadgets(), *tmpGadget)
    EndIf
  Next
EndProcedure

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Procedure WndProc(hwnd, uMsg, wParam, lParam)
  Protected result = #PB_ProcessPureBasicEvents
  
  If uMsg = #WM_EXITSIZEMOVE
    RenderGadgets(#False)
  EndIf
  
  ProcedureReturn result
EndProcedure
CompilerEndIf

RenderGadgets(#True)

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
ForEach gadgets()
  If gadgets()\Type = #PB_GadgetType_Window
    SetWindowCallback(@WndProc(), gadgets()\ID)
  EndIf
Next
CompilerEndIf

Repeat
  Define Event  = WaitWindowEvent()
  Define Gadget = EventGadget()
  Define Type   = EventType()
  Define Window = EventWindow()

  Select Event
  Case #PB_Event_Gadget
  Case #PB_Event_Menu

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
  Case #PB_Event_SizeWindow
    RenderGadgets(#False)
CompilerEndIf

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Case #PB_Event_MaximizeWindow, #PB_Event_RestoreWindow
    RenderGadgets(#False)
CompilerEndIf


  Case #PB_Event_CloseWindow
    Define Quit = 1
  EndSelect
  
Until Quit = 1

; IDE Options = PureBasic 4.40 Beta 7 (Windows - x86)
; CursorPosition = 301
; FirstLine = 239
; Folding = --
; EnableXP